import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; const SUPABASE_URL = "https://mhvphjcreqhfnulflgiy.supabase.co"; const SUPABASE_KEY = "sb_publishable_CPulXF1pmXf_7RacRrv1ag_MHuGAxXC"; const supabase = createClient(SUPABASE_URL, SUPABASE_KEY); const genres = ["All","Werewolf","Mafia","Erotica","LGBTQ","Billionaire Drama","Vampire","Paranormal","Christian Romance"]; let books = []; let selectedGenre = "All"; let currentBook = null; let chapters = []; let currentChapterIndex = 0; let reader = null; let isRegister = false; let libraryIds = new Set(); const unlockedChapterIds = new Set(); const $ = id => document.getElementById(id); function notify(message) { const toast = $("toast"); if (!toast) return; toast.textContent = message; toast.style.display = "block"; clearTimeout(window.toastTimer); window.toastTimer = setTimeout(() => toast.style.display = "none", 3500); } function escapeHTML(value = "") { return String(value).replace(/[&<>"']/g, c => ({ "&":"&","<":"<",">":">","\"":""","'":"'" })[c]); } function showPage(name) { if (name === "profile" || name === "account") name = reader ? "profile" : "account"; const page = $("page-" + name); if (!page) return; document.querySelectorAll(".page").forEach(p => p.classList.remove("active")); page.classList.add("active"); document.querySelectorAll("[data-page]").forEach(b => b.classList.toggle("active", b.dataset.page === name)); window.scrollTo({ top: 0, behavior: "smooth" }); if (name === "profile" && reader) loadProfile(); if (name === "notifications") loadNotifications(); if (name === "wallet" && reader) loadTransactions(); } function renderGenres() { ["home-genres","browse-genres"].forEach(id => { const el = $(id); if (!el) return; el.innerHTML = genres.map(g => `` ).join(""); }); } function bookCard(book) { const id = escapeHTML(book.id); const title = escapeHTML(book.title || "Untitled story"); const author = escapeHTML(book.author || book.author_name || "Fictional World"); const genre = escapeHTML(book.genre || "Fiction"); const cover = book.cover_url || book.cover_image || ""; return `
${cover ? `${title}` : ""}
${title}

${title}

${author}

${genre}
`; } function renderBookList(target, list) { const el = $(target); if (!el) return; el.innerHTML = list.length ? list.map(bookCard).join("") : `
No stories to display yet.
`; } function filteredBooks() { const q = ($("search-input")?.value || "").trim().toLowerCase(); return books.filter(b => { const genreMatch = selectedGenre === "All" || String(b.genre || "").toLowerCase() === selectedGenre.toLowerCase(); const searchMatch = !q || [b.title, b.author, b.author_name, b.genre].some(v => String(v || "").toLowerCase().includes(q)); return genreMatch && searchMatch; }); } function renderBooks() { const featured = books.filter(b => b.featured === true); renderBookList("featured-books", featured.slice(0, 5).concat(books.filter(b => !b.featured).slice(0, Math.max(0, 5 - featured.length)))); renderBookList("ongoing-books", books.filter(b => /ongoing/i.test(b.status || "")).slice(0, 5)); renderBookList("completed-books", books.filter(b => /completed/i.test(b.status || "")).slice(0, 5)); const list = filteredBooks(); renderBookList("all-books", list); const total = $("book-total"); if (total) total.textContent = `${list.length} stories`; const heading = $("browse-heading"); if (heading) heading.textContent = selectedGenre === "All" ? "All stories" : selectedGenre; renderGenres(); } async function loadBooks() { const allBooks = $("all-books"); if (allBooks) allBooks.innerHTML = `

Loading stories...

`; const { data, error } = await supabase.from("books").select("*").limit(100); if (error) { console.error("Books:", error.message); if (allBooks) allBooks.innerHTML = `
Stories could not be loaded. Please refresh and try again.
`; notify("Unable to load stories. Please try again."); return; } books = data || []; renderBooks(); }function renderPackages() { const packages = [ { id: "coins_100", coins: 100, price: "$2.99" }, { id: "coins_300", coins: 300, price: "$7.99" }, { id: "coins_600", coins: 600, price: "$14.99" }, { id: "coins_1200", coins: 1200, price: "$27.99" } ]; const el = $("coin-packages"); if (el) el.innerHTML = packages.map(p => `
Coin package

${p.coins.toLocaleString()} coins

${p.price}
` ).join(""); const plans = [ { id: "readers_pass", name: "Readers Pass", monthly: "$5.99", yearly: "$49.99", benefits: ["No banner ad","50 free coins monthly","5% off on coin purchases"] }, { id: "vip_reader", name: "VIP Reader", monthly: "$9.99", yearly: "$89.99", benefits: ["No banner ad","150 free coins monthly","9% off on coin purchases"] }, { id: "exclusive_reader", name: "Exclusive Reader", monthly: "$19.99", yearly: "$179.99", benefits: ["No banner ad","300 free coins monthly","15% off on coin purchases","2 free chapter unlocks"] } ]; const membershipEl = $("membership-plans"); if (membershipEl) membershipEl.innerHTML = plans.map((p, i) => `
${i === 1 ? "Popular choice" : "Reader membership"}

${p.name}

${p.monthly} / month

${p.yearly} when billed yearly

` ).join(""); } function updateAccountUI() { $("login-nav").textContent = "My Account"; if (!reader) { $("profile-email").textContent = "Sign in to view your profile"; $("profile-name").textContent = "Reader"; $("profile-reader-id").textContent = "—"; $("profile-gender").textContent = "Not provided"; $("profile-avatar").textContent = "♡"; return; } $("profile-email").textContent = reader.email || ""; $("profile-name").textContent = reader.user_metadata?.display_name || reader.email?.split("@")[0] || "Reader"; } async function getSession() { try { const { data: { session }, error } = await supabase.auth.getSession(); if (error) { console.error("Session error:", error); reader = null; return; } reader = session?.user || null; if (!reader) { updateAccountUI(); $("coin-count").textContent = "0"; $("wallet-coins").textContent = "0"; $("profile-coins").textContent = "0"; return; } await loadProfile(); await loadLibrary(); await loadTransactions(); await loadNotifications(); if ($("page-account") && $("page-account").classList.contains("active")) showPage("profile"); } catch (error) { console.error("Could not get session:", error); reader = null; } } async function loadProfile() { if (!reader) return; const { data, error } = await supabase.from("users").select("*").eq("auth_user_id", reader.id).maybeSingle(); if (error) console.warn("Profile load error:", error.message); const profile = data || {}; const name = profile.name || reader.user_metadata?.display_name || reader.email?.split("@")[0] || "Reader"; const avatar = profile.avatar_url || profile.profile_picture || profile.photo_url || reader.user_metadata?.avatar_url || reader.user_metadata?.picture || ""; const gender = profile.gender || reader.user_metadata?.gender || "Not provided"; const coins = Number(profile.coin_balance ?? 0); $("coin-count").textContent = coins; $("wallet-coins").textContent = coins; $("profile-coins").textContent = coins; $("profile-display-name").value = name; $("profile-name").textContent = name; $("profile-email").textContent = reader.email || profile.email || "Email not available"; $("profile-reader-id").textContent = profile.id ?? reader.id; $("profile-gender").textContent = gender; $("profile-tier").textContent = profile.subscription_tier || "Free"; $("profile-tier-stat").textContent = profile.subscription_tier || "Free"; $("profile-avatar").innerHTML = avatar ? `Profile picture` : "♡"; } async function loadLibrary() { if (!reader) { $("library-note").hidden = false; renderBookList("library-books", []); return; } const { data, error } = await supabase.from("library").select("*").eq("user_id", reader.id); if (error) { console.warn("Library load error:", error.message); return; } libraryIds = new Set((data || []).map(x => String(x.book_id))); $("profile-saved").textContent = libraryIds.size; $("library-note").hidden = libraryIds.size > 0; renderBookList("library-books", books.filter(b => libraryIds.has(String(b.id)))); } async function loadTransactions() { if (!reader) return; const { data, error } = await supabase.from("transactions").select("*").eq("user_id", reader.id).order("created_at", { ascending: false }).limit(20); if (error) { console.warn("Transactions load error:", error.message); $("transactions").innerHTML = `

Transaction history is unavailable right now.

`; return; } if (!data || data.length === 0) { $("transactions").innerHTML = `

No transactions yet.

`; return; } $("transactions").innerHTML = data.map(t => `
${t.payment_status || "Transaction"} · ${t.amount_ngn ?? 0} NGN ${t.coins_added ?? 0} coins
`).join(""); } async function loadNotifications() { const list = $("notification-list"); if (!list) return; if (!reader) { list.innerHTML = `

Log in to view your notifications.

`; return; } const { data, error } = await supabase.from("notification").select("*").eq("user_id", reader.id).order("created_at", { ascending: false }).limit(30); if (error) { console.warn("Notifications load error:", error.message); list.innerHTML = `

Notifications are unavailable right now.

`; return; } if (!data || data.length === 0) { list.innerHTML = `

You're all caught up. No notifications are available.

`; return; } list.innerHTML = data.map(n => `
${escapeHTML(n.title || "Notification")}

${escapeHTML(n.message || n.body || "")}

${new Date(n.created_at).toLocaleString()}
${escapeHTML(n.type || "info")}
`).join(""); }